using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Content;
using System.Diagnostics;
using HappyFrogXna.ScreenSystem;

namespace HappyFrogXna.ParticleSystem
{
    /// <summary>
    /// A basic particle. Since this is strictly a data class, I decided to not go
    /// the full property route and used public fields instead.
    /// </summary>
    public class Particle
    {
        public Vector2 Position;
        public Vector2 Velocity;
        public Texture2D Texture;
        public float RotationRate;
        public float Rotation;
        public float Life;
        public float AlphaRate;
        public float Alpha;
        public float ScaleRate;
        public float Scale;
        public Color Color = Color.White;
    }

    /// <summary>
    /// A relatively simple particle system.  We recycle particles instead of creating
    /// and destroying them as we need more.  "Effects" are created via factory methods
    /// on ParticleSystem, rather than a data driven model due to the relatively low
    /// number of effects.
    /// </summary>
    public class ParticleCreator
    {
        Texture2D boom;
        Texture2D woodFragment;
        Texture2D iceFragment;
        Texture2D stoneFragment;

        Random random;
        //SpriteBatch spriteBatch;
        List<Particle> particles;

        private static ParticleCreator _instance = null;
        public static ParticleCreator Instance 
        { 
            get 
            {
                if (_instance == null)
                    _instance = new ParticleCreator();
                return _instance; 
            } 
        }

        private ParticleCreator()
        {
            random = new Random();

            particles = new List<Particle>();

            boom = GolbalXnaGadgetProvider.Instance.Content.Load<Texture2D>(@"Images\smoke");
            woodFragment = GolbalXnaGadgetProvider.Instance.Content.Load<Texture2D>(@"Images\woodFragment");
            iceFragment = GolbalXnaGadgetProvider.Instance.Content.Load<Texture2D>(@"Images\iceFragment");
            stoneFragment = GolbalXnaGadgetProvider.Instance.Content.Load<Texture2D>(@"Images\stoneFragment");
        }

        /// <summary>
        /// Update all active particles.
        /// </summary>
        /// <param name="elapsed">The amount of time elapsed since last Update.</param>
        public void Update(float elapsedInMillisecond)
        {
            for (int i = 0; i < particles.Count; ++i)
            {
                if (particles[i].Life <= 0.0f)
                {
                    continue;
                }
                particles[i].Life -= elapsedInMillisecond;
                float elapsed = elapsedInMillisecond / 1000;
                particles[i].Position += particles[i].Velocity * elapsed;
                particles[i].Rotation += particles[i].RotationRate * elapsed;
                particles[i].Alpha += particles[i].AlphaRate * elapsed;
                particles[i].Scale += particles[i].ScaleRate * elapsed;

                if (particles[i].Alpha <= 0.0f)
                    particles[i].Alpha = 0.0f;
            }
        }

        /// <summary>
        /// Draws the particles.
        /// </summary>
        public void Draw()
        {
            for (int i = 0; i < particles.Count; ++i)
            {
                Particle p = particles[i];
                if (p.Life <= 0.0f)
                    continue;

                float alphaF = 255.0f * p.Alpha;
                if (alphaF < 0.0f)
                    alphaF = 0.0f;
                if (alphaF > 255.0f)
                    alphaF = 255.0f;

                GolbalXnaGadgetProvider.Instance.SpriteBatch.Draw(p.Texture, p.Position, null, new Color(p.Color.R, p.Color.G, p.Color.B, (byte)alphaF), 
                    p.Rotation, new Vector2(p.Texture.Width / 2, p.Texture.Height / 2), p.Scale, SpriteEffects.None, 0.0f);
            }
        }

        /// <summary>
        /// Creats a particle, preferring to reuse a dead one in the particles list 
        /// before creating a new one.
        /// </summary>
        /// <returns></returns>
        Particle CreateParticle()
        {
            Particle p = null;

            for (int i = 0; i < particles.Count; ++i)
            {
                if (particles[i].Life <= 0.0f)
                {
                    p = particles[i];
                    break;
                }
            }

            if (p == null)
            {
                p = new Particle();
                particles.Add(p);
            }

            p.Color = Color.White;

            return p;
        }

        /// <summary>
        /// Creats the effect for when an animal dies.
        /// </summary>
        /// <param name="position">Where on the screen to create the effect.</param>
        public void CreateAnimalExplosion(Vector2 position)
        {
            Particle p = null;

            for (int i = 0; i < 8; ++i)
            {
                p = CreateParticle();
                p.Position = position;
                p.RotationRate = -6.0f + 12.0f * (float)random.NextDouble();
                p.Scale = 0.1f;
                p.ScaleRate = (float)random.NextDouble() * 0.15f + 0.1f;
                p.Alpha = 2.0f;
                p.AlphaRate = -0.7f;
                p.Velocity.X = -4.0f + 8.0f * (float)random.NextDouble();
                p.Velocity.Y = -4.0f + 8.0f * (float)random.NextDouble();
                p.Texture = boom;
                p.Life = 2200.0f;
            }
        }

        public void CreateWoodExplosion(Vector2 position)
        {
            CreateEntityExplosion(position, woodFragment);
        }

        public void CreateIceExplosion(Vector2 position)
        {
            CreateEntityExplosion(position, iceFragment);
        }

        public void CreateStoneExplosion(Vector2 position)
        {
            CreateEntityExplosion(position, stoneFragment);
        }

        /// <summary>
        /// Creats the effect for when an entity crash.
        /// </summary>
        /// <param name="position">Where on the screen to create the effect.</param>
        public void CreateEntityExplosion(Vector2 position, Texture2D fragmentTexture)
        {
            Particle p = null;

            for (int i = 0; i < 6; ++i)
            {
                p = CreateParticle();
                p.Position = position + new Vector2((float)random.NextDouble() * 32f, (float)random.NextDouble() * 32f);
                p.RotationRate = -3.0f + 6.0f * (float)random.NextDouble();
                p.Scale = 1f;
                p.ScaleRate = (float)random.NextDouble() * 0.15f + 0.1f;
                p.Alpha = 1.0f;
                p.AlphaRate = 0;
                p.Velocity.X = -16.0f + 32.0f * (float)random.NextDouble();
                p.Velocity.Y = -16.0f + 32.0f * (float)random.NextDouble();
                p.Texture = fragmentTexture;
                p.Life = 1200.0f;
            }
        }

    }
}
